﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;

using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace SeverVisual
{
    public partial class Server : Form
    {
        private   Socket serverSocketTcp;
        private   Socket serverSocketUdp;
        private   bool type = false; //true为异步，false为同步
        private   string[] receiver;//文件指定发送接收者
        private   Dictionary<string, Socket> userList = new Dictionary<string, Socket>();
        public Server()
        {
            InitializeComponent();
        }

        private void label1_Click(object sender, EventArgs e)
        {

        }

        private void listView1_SelectedIndexChanged(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            Socketinit();
            printLog("服务器开启");
           
        }


        public void Socketinit()
        {

            //封装IP和端口
            IPEndPoint endPointTcp = new IPEndPoint(IPAddress.Parse(textIP.Text),Convert.ToInt32(textPort.Text));
            IPEndPoint endPointUdp = new IPEndPoint(IPAddress.Parse("127.0.0.1"), 4321);

            //实例化套接字
            serverSocketTcp = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            serverSocketTcp.Bind(endPointTcp);

            serverSocketUdp = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            serverSocketUdp.Bind(endPointUdp);

            //开始监听
            serverSocketTcp.Listen(100);
            
            printLog("开始监听TCP");

            //开始监听
            //printLog("开始监听UDP");
            //Udp不用监听

            if (type)
            {
                printLog("异步");
                //异步方式
                serverSocketTcp.BeginAccept(new AsyncCallback(ClientConnAsync), serverSocketTcp);
            }
            else
            {
                printLog("同步");
                //同步方式
                ThreadPool.QueueUserWorkItem(new WaitCallback(ClientConn));
                //Thread threadlisten = new Thread(ClientConn);
                //threadlisten.IsBackground = true;
                //threadlisten.Start();
            }
            printLog("开始监听.......");
            //printLog("开启监听。。。");
            //printLog("点击输入任意数据回车退出程序。。。");
            //Console.ReadKey();
            //printLog("退出监听，并关闭程序。");

        }
        //同步连接
        private   void ClientConn(object obj)
        {
            while (true)
            {
                Socket socketConn = serverSocketTcp.Accept();
                ClientOption(socketConn);
            }

        }
        //异步连接
        private   void ClientConnAsync(IAsyncResult ar)
        {
            try
            {
                Socket SocketTemp = ar.AsyncState as Socket;
                Socket socketConn = null;
                socketConn = SocketTemp.EndAccept(ar);

                ClientOption(socketConn);
                //准备接受下一个客户端请求
                if (SocketTemp != null) SocketTemp.BeginAccept(new AsyncCallback(ClientConnAsync), SocketTemp);
            }
            catch
            {

            }
            

        }

          void ClientOption(Socket socketConn)
        {
            //获取IP和端口
            IPAddress iPAddress = (socketConn.RemoteEndPoint as IPEndPoint).Address;
            int Port = (socketConn.RemoteEndPoint as IPEndPoint).Port;
            // 提示客户端连接成功并告诉他端口号 标志字段为t 116
            socketConn.Send(Encoding.UTF8.GetBytes("t连接服务端成功！\r\n" + "本地IP: " + iPAddress + "，本地端口" + Port));
            //获取客户端连接信息并打印
            string remoteEndPoint = socketConn.RemoteEndPoint.ToString();
            printLog("连接成功" + remoteEndPoint);
            //客户端登录标识符为l 向所有客户端通知新登录的小伙子
            byte[] msg = new byte[1024];
            //添加客户信息到当前登录的列表
            userList.Add(iPAddress + ":" + Port.ToString(), socketConn);
            //建立线程进行处理
            ParameterizedThreadStart pts = new ParameterizedThreadStart(recv);
            Thread thread = new Thread(pts);
            thread.IsBackground = true;
            thread.Start(socketConn);
        }

        //服务器收到信息
         private void recv(object socketclient)
        {
            Socket socketMsgServer = socketclient as Socket;
            try
            {
                
                while (true)
                {
                    EndPoint endPointAll = new IPEndPoint(IPAddress.Any, 0);
                    byte[] msgArryTemp = new byte[1024 * 5];
                    //接受数据，返回长度
                    int TrueClientMsgLength = socketMsgServer.Receive(msgArryTemp);
                    byte[] msgArry = new byte[TrueClientMsgLength];
                    Array.Copy(msgArryTemp, 0, msgArry, 0, TrueClientMsgLength);
                    //控制台打印客户端数据
                    //printLog("收到客户端"+ (socketMsgServer.RemoteEndPoint as IPEndPoint).Address + (socketMsgServer.RemoteEndPoint as IPEndPoint).Port +"数据 "+"长度"+msgArry.Length);
                    //socketMsgServer.Send(msgArry);
                    string ip = (socketMsgServer.RemoteEndPoint as IPEndPoint).Address.ToString();
                    string port = (socketMsgServer.RemoteEndPoint as IPEndPoint).Port.ToString();
                    Seversend(socketMsgServer, msgArry, ip, port);
                }
            }
            catch
            {   
                printLog((socketMsgServer.RemoteEndPoint as IPEndPoint).Address.ToString()+":"+(socketMsgServer.RemoteEndPoint as IPEndPoint).Port+ "离开了我们");
                userList.Remove((socketMsgServer.RemoteEndPoint as IPEndPoint).Address+":"+(socketMsgServer.RemoteEndPoint as IPEndPoint).Port);
            }  
         }
      
        //获取消息类型并处理
        private   void Seversend(object SeverSend, byte[] data, string ip, string port)
        {
            Socket Send = SeverSend as Socket;
            try
            {
                //拆解消息头信息
                byte msgType = data[0];
                byte[] msgContent = new byte[data.Length];
                Buffer.BlockCopy(data, 1, msgContent, 0, data.Length - 1);

                // 获取发送时间
                string timeStamp = DateTime.Now.ToString();

                //判断类型并发送
                switch (msgType)
                {
                    // 112 标识符为p，表示群发
                    case 112:
                        {
                            printLog("收到来自"+ip+" " + port + "的群发文本:"+Encoding.UTF8.GetString(msgContent));
                            foreach(string str in userList.Keys)
                            {
                                if (str != ip + ":" + port)
                                {
                                userList[str].Send(assembly("p", ip, port, timeStamp, msgContent));
                                }
                            }
                        }
                        break;
                        // 102 f 文件群发
                    case 102:
                        {
                            printLog("收到来自" + ip + " " + port + "的群发文件数据包 长度:" + data.Length);
                            foreach (string str in userList.Keys)
                            {
                                if (str != ip + ":" + port)
                                {
                                    userList[str].Send(data);
                                }
                            }
                        }
                        break;
                        //105 i 文件私发
                    case 105:
                        {
                            if(data[1] == '#')
                            {
                                printLog("收到来自" + ip + " " + port + "的定向发送文件数据包 长度:" + data.Length);
                                receiver = Encoding.UTF8.GetString(data).Split('#');
                                for (int i = 3; i < receiver.Length - 1; i++)
                                {
                                    userList[receiver[i]].Send(data);
                                    printLog("发送给" + receiver[i]);
                                }

                            }
                            else
                            {
                                printLog("收到来自" + ip + " " + port + "的定向发送文件数据包 长度:" + data.Length);
                                for (int i = 3; i < receiver.Length - 1; i++)
                                {
                                    userList[receiver[i]].Send(data);
                                    printLog("发送给" + receiver[i]);
                                }
                            }
                        }
                        break;
                    // 108 标识符为l,暂时搁置
                    case 108:
                        {

                        }
                        break;
                    // 115 标识符为s,发给指定用户
                    case 115:
                        {
                            string msg = Encoding.UTF8.GetString(msgContent);
                            string[] temp = msg.Split('#');
                            printLog("收到来自" + ip + " " + port + "的定向发送文本数据：" + temp[temp.Length - 1]);
                            for (int i = 0; i < temp.Length - 1; i++)
                            {
                                userList[temp[i]].Send(assembly("s", ip, port, timeStamp, Encoding.UTF8.GetBytes(temp[temp.Length - 1])));
                                printLog("发送给" + temp[i]);
                            }
                        }
                        break;
                    // 103 标识符为g,获取在线用户
                    case 103:
                        {
                            byte[] msg = new byte[1024];
                            string userlist = "g";
                            printLog("收到来自" + ip + " " + port + "的获取在线用户的请求");
                            foreach (string usetInfo in userList.Keys)
                            {
                                userlist += usetInfo + "#";
                            }
                            Send.Send(Encoding.UTF8.GetBytes(userlist));
                        }
                        break;
                }

            }
            catch
            {
                Send.Send(Encoding.UTF8.GetBytes("t服务器异常"));
            }


        }
        private   byte[] assembly(string type, string ip , string port, string timeStamp, byte[] msgContent)
        {
            string Content = type + ip + ":" + port + "-" + timeStamp + ":" + Encoding.UTF8.GetString(msgContent);
            byte[] msg = new byte[Content.Length];
            msg = Encoding.UTF8.GetBytes(Content);
            return msg;
        }
        private void printLog(string str)
        {
            textLog.AppendText("\r\n"+str);
        }

       

        private void textLog_TextChanged(object sender, EventArgs e)
        {

        }

        private void button3_Click(object sender, EventArgs e)
        {
            checkedListBox1.Items.Clear();
            foreach(string user in userList.Keys)
            {
                checkedListBox1.Items.Add(user);
            }
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //取消跨线程检查
            Control.CheckForIllegalCrossThreadCalls = false;
        }
        

        private void button2_Click(object sender, EventArgs e)
        {
            textLog.Clear();
        }

        private void Server_FormClosing(object sender, FormClosingEventArgs e)
        {
            Application.Exit();
        }
    }
}
